	title	'LDRBIOS for CP/M 3.0'

        .z80

cr	equ 13
lf	equ 10
ntry    equ 4                   ; number of retries for disk read

        external adrv,dskdef    ; drive & disk tables

origin	equ     0E000H
djboot	equ     origin          ;Disk Jockey 2D cold boot
djcin	equ     origin+3h       ;Disk Jockey 2D character input routine
djcout	equ	origin+6h	;Disk Jockey 2D character output routine
djhome	equ	origin+9h	;Disk Jockey 2D track zero seek
djtrk	equ	origin+0ch	;Disk Jockey 2D track seek routine
djsec	equ	origin+0fh	;Disk Jockey 2D set sector routine
djdma	equ	origin+12h	;Disk Jockey 2D set DMA address
djread	equ	origin+15h	;Disk Jockey 2D read routine
djwrit	equ	origin+18h	;Disk Jockey 2D write routine
djsel	equ	origin+1bh	;Disk Jockey 2D select drive routine
djtsta	equ	origin+21h	;Disk Jockey 2D terminal status routine
djstat	equ	origin+27h	;Disk Jockey 2D status routine
djerr	equ	origin+2ah	;Disk Jockey 2D error, flash led
djden	equ	origin+2dh	;Disk Jockey 2D set density routine
djside	equ	origin+30h	;Disk Jockey 2D set side routine
djleav  equ     origin+222h     ;leave routine in dj rom
djprep  equ     origin+233h     ;prep routine in dj rom

    ; BIOS Jump vector.

?boot:	jp boot         ; initial entry on cold start
?wboot:	jp wboot	; reentry on program exit, warm start

?const:	jp const	; return console input status
?conin:	jp conin	; return console input character
?cono:	jp conout	; send console output character
?list:	jp list 	; send list output character
?auxo:	jp auxout	; send auxilliary output character
?auxi:	jp auxin	; return auxilliary input character

?home:	jp home 	; set disks to logical home
?sldsk:	jp seldsk	; select disk drive, return disk parameter info
?sttrk:	jp settrk	; set disk track
?stsec:	jp setsec	; set disk sector
?stdma:	jp setdma	; set disk I/O memory address
?read:	jp read 	; read physical block(s)
?write:	jp write	; write physical block(s)

?lists:	jp listst	; return list device status
?sctrn:	jp sectrn	; translate logical to physical sector

?conos:	jp conost	; return console output status
?auxis:	jp auxist	; return aux input status
?auxos:	jp auxost	; return aux output status
?dvtbl:	jp devtbl	; return address of device def table
?devin:	jp cinit	; change baud rate of device

?drtbl:	jp getdrv	; return address of disk drive table
?mltio:	jp multio	; set multiple record count for disk I/O
?flush:	jp flush	; flush BIOS maintained disk caching

?mov:	jp move 	; block move memory to memory
?tim:	jp time 	; Signal Time and Date operation
?bnksl:	jp bnksel	; select bank for code execution and default DMA
?stbnk:	jp setbnk	; select different bank for disk I/O DMA operations.
?xmov:	jp xmove	; set source and destination banks for one operation

	jp fe		; reserved for future expansion
	jp fe		; reserved for future expansion
	jp fe		; reserved for future expansion


wboot:                  ; jump vector locations not used
const:
conin:
list:
auxout:
auxin:
write:
listst:
conost:
auxist:
auxost:
devtbl:
cinit:
getdrv:
multio:
flush:
time:
bnksel:
setbnk:
xmove:
fe:     ld hl,msg1               ; error halt
        call ?pmsg
        halt
msg1:   db cr,lf,'CPMLDR failure: unimplemented bios call',cr,lf,0


boot:
        ld a,1                   ; reset output board
        out (0e1h),a
        ld a,0
        out (0e1h),a

; get disk type - assume reads of a non-zero track have already taken place
; so a dummy read is not necessary - adjust disk tables and set double
; sided indicator

        call djstat              ; get status word
        ld (dsx),a               ; store for double sided indicator
        rrca                     ; move right 
        and 16h                  ; 2 * sec.lng.code + 16 * side.code
        ld hl,dskdef             ; get table of disk table addresses
        ld b,0
        ld c,a
        add hl,bc                ; hl points to address of skew table
        ld de,adrv               ; de points to head of dph
        ldi                      ; copy two bytes
        ldi
        ld bc,6
        add hl,bc                ; address of pointer to dpb
        ld bc,10
        ex de,hl
        add hl,bc                ; pointer to dpb in dph
        ex de,hl
        ldi                      ; copy two bytes
        ldi

        ret

home:   call djhome
        ret

seldsk: ld hl,adrv
        ret

settrk: ld b,c
        ld c,0
        ld a,(dsx)               ; get status word
        and 20h                  ; get bit 5
        jr z,ss                  ; jump if single sided
        srl b                    ; divide by 2
        rl c                     ;    remainder to c
ss:     call djside
        ld c,b
        call djtrk
        jr c,lmsg3
        ret

setsec: call djsec
        jr c,lmsg3
        ret
        
setdma: xor a
        call djdma
        and a
        jr nz,lmsg3
        ret

lmsg3:  ld hl,msg3
        call ?pmsg
        halt
msg3:   db cr,lf,'CPMLDR failure: disk parameter error',cr,lf,0

read:   ld b,ntry                ; number of tries
cycr:   push bc
        call djread
        pop bc
        ld a,0
        ret nc
        djnz cycr
        ld hl,msg4
        call ?pmsg
        halt
msg4:   db cr,lf,'CPMLDR error: disk read error',cr,lf,0

sectrn: ex de,hl
        add hl,bc
        ld l,(hl)
        ld h,0
        ret

conout: in a,(0e1h)             ; get status
        and 1
        jr nz,conout            ; wait for buffer to clear
        ld a,c
        and 7fh                 ; blank parity
        out (0e0h),a            ; output character
        ret

move:
	ex de,hl                ; we are passed source in DE and dest in HL
	ldir                    ; use Z80 block move instruction
	ex de,hl                ; need next addresses in same regs
	ret

?pmsg:                          ; print message @<HL> up to a null
	ld a,(hl) 
        or a 
        ret z
	ld c,a 
        push hl
	call ?cono 
        pop hl
	inc hl 
        jr ?pmsg

dsx:    ds 1                    ; indicator for double sided disks

        end
